/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { ref, Ref, defineComponent, watch, onMounted, nextTick } from 'vue';
import { toNumber, isNumber, isObject } from 'lodash-es';
import { INavigateParamContainer } from '@ibiz/model-core';
import { CodeListItem } from '@ibiz-template/runtime';
import {
  getDropdownProps,
  getEditorEmits,
  useNamespace,
  useCodeListListen,
} from '@ibiz-template/vue3-util';
import { OdooStatusBarEditorController } from './odoo-status-bar-editor.controller';
import './odoo-status-bar.scss';
import { formatSecondsToDateTime } from './use-util';

export const OdooStatusBar = defineComponent({
  name: 'IBizOdooStatusBar',
  props: getDropdownProps<OdooStatusBarEditorController>(),
  emits: getEditorEmits(),
  setup(props, { emit }) {
    const ns = useNamespace('odoo-status-bar');
    const c = props.controller;
    const editorModel = c.model;

    const codeListItems: Ref<readonly IData[]> = ref([]);
    const items: Ref<readonly IData[]> = ref([]);

    // 当前值
    const curValue = ref();

    // 是否已加载代码表
    const isLoadedCodeList = ref(false);

    // 编辑器Ref
    const editorRef = ref();

    // 更多按钮ref
    const moreButtonRef = ref();

    // 更多气泡ref
    const moreLeftRef = ref();
    const moreRightRef = ref();

    // 值项
    const { editorItems } = c.model;

    // 是否正在加载
    const isLoading = ref(false);

    // 代码项值是否为数值
    const codeItemValueNumber = ref(false);

    // 持续时间跟踪值
    const durationTrackingVal = ref<IData>({});

    // 显示项限制数量
    let maxVisible: number | undefined;
    // 持续时间属性
    let durationTracking: string | undefined;
    // 精准模式
    let accurate = false;
    if (editorModel.editorParams) {
      if (editorModel.editorParams.maxvisible) {
        maxVisible = toNumber(editorModel.editorParams.maxvisible);
      }
      if (editorModel.editorParams.duration_tracking) {
        durationTracking = editorModel.editorParams.duration_tracking;
      }
      if (editorModel.editorParams.accurate) {
        accurate = c.toBoolean(editorModel.editorParams.accurate);
      }
    }

    watch(
      () => [codeListItems.value.length, curValue.value],
      () => {
        // 默认从 selectedIndex 左侧展开
        let start: number = NaN;
        let end: number = NaN;
        if (isNumber(maxVisible)) {
          const totalItems = codeListItems.value.length;
          const selectedIndex = codeListItems.value.findIndex(
            _item => _item.id === curValue.value,
          );

          // 可见项中心点（向下取整）
          const centerIndex = Math.floor(maxVisible / 2);
          start = selectedIndex - centerIndex;

          // 防止 start 小于 0
          if (start < 0) {
            start = 0;
          }

          // 修正：若从 start 起无法展示 maxVisible 项，则向左偏移 start，使能展示完整 visibleItems
          if (start + maxVisible > totalItems) {
            start = Math.max(0, totalItems - maxVisible);
          }

          end = Math.min(totalItems, start + maxVisible);
        }

        // 适配下标在最后时不满足最大显示项的情况，选中下标在最后，右侧没有值了
        const visibleItems: IData[] = [];
        const leftHidden: IData[] = [];
        const rightHidden: IData[] = [];
        codeListItems.value.forEach((_item, index) => {
          if (index < start) {
            leftHidden.push(_item);
          } else if (index >= end) {
            rightHidden.push(_item);
          } else {
            visibleItems.push(_item);
          }
        });
        const _items = [];
        if (leftHidden.length > 0)
          _items.push({
            _type: 'more',
            _position: 'left',
            children: leftHidden,
          });

        _items.push(...visibleItems);

        if (rightHidden.length > 0)
          _items.push({
            _type: 'more',
            _position: 'right',
            children: rightHidden,
          });
        items.value = _items;
      },
    );

    /**
     * 加载代码表后续处理
     *
     * @param {readonly} codeList
     * @param {*} CodeListItem
     * @param {*} []
     */
    const afterLoadCodeList = (codeList: readonly CodeListItem[]) => {
      codeListItems.value = [];
      codeListItems.value = [];
      if (c.multiple && !codeList.some(item => item.children)) {
        // eslint-disable-next-line no-param-reassign
        codeList = c.handleCodeListAllItems(codeList);
      }
      if (c.blankItemName && !c.multiple) {
        codeListItems.value = [
          {
            value: undefined,
            text: c.blankItemName,
          },
          ...codeList,
        ];
      } else {
        codeListItems.value = codeList;
      }
    };

    // 加载代码表数据
    const loadCodeList = async () => {
      if (c.model.appCodeListId) {
        const app = ibiz.hub.getApp(c.context.srfappid);
        const codeListModel = app.codeList.getCodeList(c.model.appCodeListId);
        if (codeListModel) {
          codeItemValueNumber.value =
            codeListModel.codeItemValueNumber || false;
        }
      }
      isLoading.value = true;
      const codeList = await c.loadCodeList(props.data!);
      afterLoadCodeList(codeList);
      isLoadedCodeList.value = true;
      isLoading.value = false;
    };

    watch(
      () => props.value,
      async (newVal, oldVal) => {
        if (newVal || newVal === null || newVal === 0) {
          // 值从无到有、并且没搜索过的情况
          if (!isLoadedCodeList.value && oldVal === undefined) {
            await loadCodeList();
          }
        }
        if (newVal !== oldVal) {
          // 单选才考虑值项
          if (editorItems && editorItems.length > 0) {
            curValue.value = props.data[editorItems[0].id!]?.toString();
          } else {
            curValue.value = newVal;
          }
        }
      },
      { immediate: true },
    );

    const useEditorNavParams = (): void => {
      const { navigateContexts = [], navigateParams = [] } =
        c.model as INavigateParamContainer;
      const navParamName: string[] = [];
      [...navigateContexts, ...navigateParams].forEach(nav => {
        if (!nav.rawValue && nav.value) {
          navParamName.push(nav.value);
        }
      });
      // 导航参数发生改变时重新加载数据
      watch(
        () => {
          // 直接监听props.data时 newVal, oldVal 值一样，所以在这直接监听导航参数数据项变化
          const data: IData = {};
          Object.keys(props.data).forEach(key => {
            if (navParamName.includes(key)) {
              data[key] = props.data[key];
            }
          });
          return data;
        },
        () => {
          if (props.data) {
            loadCodeList();
            const parentData = props.data;
            if (
              durationTracking &&
              parentData[durationTracking] &&
              isObject(parentData[durationTracking])
            ) {
              durationTrackingVal.value = parentData[durationTracking];
            }
          }
        },
        { deep: true },
      );
    };

    const fn = (data: CodeListItem[] | undefined) => {
      if (data) afterLoadCodeList(data);
    };

    useCodeListListen(c.model.appCodeListId, c.context.srfappid, fn);

    onMounted(() => {
      useEditorNavParams();
    });

    const handleItemClick = (_e: MouseEvent, selectItem: IData) => {
      const select = selectItem.id;
      if (editorItems && editorItems.length > 0) {
        // 有值项 默认抛标题 值项抛实际value
        let emitVal: number | string | undefined | null = select;
        if (codeItemValueNumber.value) {
          emitVal = select === '' ? null : Number(select);
        }
        emit('change', emitVal, editorItems[0].id!);
        if (selectItem) {
          emit('change', selectItem.text);
        }
      } else {
        let emitVal: number | string | undefined | null = select;
        if (codeItemValueNumber.value) {
          emitVal = select === '' ? null : Number(select);
        }
        emit('change', emitVal);
      }

      moreLeftRef.value?.hide();
      moreRightRef.value?.hide();
      nextTick(() => {
        (c.parent as IData)?.form?.save({ silent: true });
      });
    };

    const renderItem = (_item: IData) => {
      const dateTime = formatSecondsToDateTime(
        durationTrackingVal.value[_item.id],
        accurate,
      );
      return (
        <button
          class={[ns.e('item'), ns.is('current', _item.id === curValue.value)]}
          disabled={
            _item.disableSelect === true || props.disabled || props.readonly
          }
          onClick={_e => handleItemClick(_e, _item)}
        >
          <span class={ns.em('item', 'caption')}>{_item.text}</span>
          {dateTime && <span class={ns.em('item', 'time')}>{dateTime}</span>}
        </button>
      );
    };
    const renderMore = (_item: IData) => {
      const { children, position } = _item;
      return [
        <button ref='moreButtonRef' class={[ns.e('item'), ns.e('more')]}>
          <svg
            class='icon'
            viewBox='0 0 1024 1024'
            version='1.1'
            xmlns='http://www.w3.org/2000/svg'
            height='1em'
            width='1em'
          >
            <path d='M147.01175 430.890704c-44.791136 0-81.108273 36.303834-81.108273 81.109296 0 44.778856 36.316114 81.108273 81.108273 81.108273 44.792159 0 81.109296-36.329417 81.109296-81.108273C228.121046 467.194538 191.804932 430.890704 147.01175 430.890704zM511.999488 430.890704c-44.791136 0-81.108273 36.303834-81.108273 81.109296 0 44.778856 36.316114 81.108273 81.108273 81.108273 44.792159 0 81.109296-36.329417 81.109296-81.108273C593.108784 467.194538 556.791647 430.890704 511.999488 430.890704zM876.987227 430.890704c-44.791136 0-81.108273 36.303834-81.108273 81.109296 0 44.778856 36.316114 81.108273 81.108273 81.108273s81.108273-36.329417 81.108273-81.108273C958.094476 467.194538 921.778362 430.890704 876.987227 430.890704z'></path>
          </svg>
        </button>,
        <el-popover
          ref={position === 'left' ? 'moreLeftRef' : 'moreRightRef'}
          width='auto'
          placement='bottom-end'
          trigger='click'
          popper-class={ns.e('popover')}
          virtual-ref={moreButtonRef}
          virtual-triggering
        >
          {{
            default: () => {
              return (
                <div class={ns.em('popover', 'content')}>
                  {children.map((_item2: IData) => {
                    return renderItem(_item2);
                  })}
                </div>
              );
            },
          }}
        </el-popover>,
      ];
    };

    return {
      ns,
      c,
      editorRef,
      moreButtonRef,
      moreLeftRef,
      moreRightRef,
      codeListItems,
      curValue,
      isLoading,
      items,
      handleItemClick,
      renderItem,
      renderMore,
    };
  },

  render() {
    return (
      <div
        class={[
          this.ns.b(),
          this.disabled ? this.ns.m('disabled') : '',
          this.readonly ? this.ns.m('readonly') : '',
        ]}
      >
        {this.items.map(_item => {
          return _item._type === 'more'
            ? this.renderMore(_item)
            : this.renderItem(_item);
        })}
      </div>
    );
  },
});
